■ 内臓 A/Dコンバータの読込み
PIC16、18、dsPICシリーズでは8〜12ビットの内臓A/Dコンバータが内臓されているPICがあります。
■ CCSコンパイラ
CCSコンパイラでははA/Dコンバータ読込みに関して以下の4つの例を紹介します。
(1) 8ビットA/Dコンバータ出力を8個のLEDで表示
(2) 8ビットA/Dコンバータ出力を液晶に表示
(3) 基準電圧による正確な10ビットA/D変換
(4) AD変換を2つ使用した高分解能10ビットA/D変換
■ C18コンパイラ
(1) 入力電圧を液晶に表示(PIC18F4550)
(2) 入力電圧を液晶に表示(PIC18F452)
■ C30コンパイラ dsPIC編
(1) 入力電圧を液晶に表示(dsPIC30F2012)
(2) 入力電圧を液晶に表示(dsPIC30F4013)
■ C30コンパイラ PIC24編
入力電圧を液晶に表示(PIC24FJ64GA002)
■ C32コンパイラ PIC32MX編
入力電圧を液晶に表示(PIC32MX460F512L)
A/Dコンバータの読み込み方はすべて同じで以下のようになります。(詳細 コンパイラのヘルプ参照)
記載 順番 |
ソースコードへの記載要領 | 例 |
1. | プリプロセッサにおいて使用するPICのヘッダーファイルをインクルードします. すぐあとの行にA/Dコンバータの分解能に関する記載をおこなます |
#include <pic16f877.h> #device ADC=10 |
2. | 使用するクロック周波数に関する記載をおこなう | #use delay(clock=20000000) |
3. | A/D変換した値を格納する変数を設定します 8ビットのA/Dの場合はunsigned int型を、10〜12ビットのA/Dの場合は long int型またはunsigned long int型の整数を設定します。 |
unsigned int Advalue; |
4. | A/D変換に関係するポートをアナログポートとして使用するのか、デジタルポートとして使用するのか、またA/D変換する際の基準電圧端子として使用するかといった設定をおこないます。 | setup_adc__ports( ALL_ANALOG ); |
5. | PICの内臓A/Dコンバータは逐次比較型です。変換に際し使用するクロックとして何をつかうのかを main関数のはじめで設定します。 通常は内部クロックをつかいます。 | setup_adc(ADC_CLOCK_INTERNAL); |
6. | どのポートのアナログ値を読むのか指定します。PICは複数のA/D変換ができるポートをもっていますが、逐次比較レジスタ、D/A変換器、及び これらの制御部を1つしかもっていいないので切り替えて使います。同時には読み込めません。 | set_adc_channel(2); |
7. | チャンネルを切り替えた後、A/D変換されたデジタル値がセットされるまでの時間(トータルセトリング時間)+αの時間だけ待ちます | delay_us(50); |
8. | A/D変換された値を読み込み、変数にセットします。 read_adc();の戻り値についてコンパイラのリファレンスマニュアルには Returns: Either a 8 or 16 bit int depending on #DEVICE ADC= directive. とあります。 実際に観測してみると戻ってくるのは符合なし整数です。戻り値の変数の型は符号なしの整数にするようにしましょう。 10ビットAD変換の時は変数の型をlong int (16ビット)にするので整数でも符号なし整数でも問題は発生しません。しかし、8ビットAD変換の時変数の型をint型(8ビット)にすると基準電圧の1/2以上の値に対し戻り値は負となってしまいます。(2)8ビットA/Dコンバータ出力を液晶に表示 を参照して下さい。 |
Advalue = read_adc(); |
以下のプログラム例の中にある液晶表示器制御ライブラリ 1llcd_lib.cは 後閑哲也さんが設計されたものです。
<試作品仕様>
・ 可変抵抗器で0〜5Vの電圧をつくり、ポートAN0に入力すること
・ AN0に入力された電圧をPICの電源電圧+5Vを比較基準電圧として8ビットのA/Dコンバータで読み込むこと
・ A/D変換された8ビット値を LSB(第0位ビット)→RB0、第1位ビット→RB1、…… MSB(第7位ビット)→RB7、
となるように対応させ、A/Dコンバータの値にしたがってLEDを点滅させること
・ 入力電圧が0Vの時LEDはすべてOFF、5Vの時はすべて点灯させること
<試作品回路図>
PIC16F877をつかった場合の回路図を以下に示します。(→回路図のPDFファイル)
<試作品外観>
<プログラム例>
/* ----------------------------------------------------------------------------------------- PIC16F877 内臓ADコンバータを8ビットの分解能で使ってアナログ電圧を読み込み値を8個のLEDで表示する ------------------------------------------------------------------------------------------- */ #include "16f877.h" #device ADC=8 // 10ビットにもなるADコンバータではあるが 8ビットのADコンバータにセット #use delay(clock=20000000) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #byte port_b=6 //Bポートレジスタ(6番地)を 変数port_bに対応させる main(){ unsigned int unsignedintX; set_tris_b(0); //Bポートの端子をすべて出力モード "0" に設定 setup_adc_ports(ALL_ANALOG); //AN0〜AN7すべてをA/D変換入力ポートに設定 setup_adc(ADC_CLOCK_INTERNAL); //逐次変換して比較する時、内部クロックを使用する while(1) { set_adc_channel(0); // チャンネルAN0のADコンバータ変換開始 delay_us(50); //A/D変換されたデジタル値がセットされるまでの時間(トータルセトリング時間)+αの時間だけ待ちます unsignedintX = read_adc(); //A/D変換された値を読み込み、符号なし整数の変数にセットします port_b = ~(unsignedintX); //BポートにAD変換されたデジタル値を反転して出力する } return 0; }
(2) 8ビットA/Dコンバータ出力を液晶に表示
AD変換された値を整数でよみとると比較電圧の1/2より大きい電圧に対しては値が負になると同時に電圧が大きく
なるにしたがって値の絶対値が減少していきます。
入力電圧 小 1/2
大
整数 0 1 2 …… 125 126
127 -128 -127 -126 -125 ……
-3 -2 -1
符号なし整数 0 1 2
…… 125 126 127 128
129 130 131
253 254 255
この問題は8ビットA/D変換の時変数をint型(8ビット)にした場合に発生します。 read_adc();の戻り値は符号
なしの整数なので変数は符号なしの整数にした方がよいと思います。 尚、変数の型を long int型(16ビット)に
しておけば比較電圧の1/2以上で負になるこのトラブルはA/Dが10ビット変換の場合も含め発生しません
<試作品仕様>
・ 可変抵抗器で0〜5Vの電圧をつくり、ポートAN0に入力すること
・ AN0に入力された電圧をPICの電源電圧+5Vを比較基準電圧として8ビットのA/Dコンバータで読み込むこと
・ A/D変換された値を(符号付)整数で受け取り液晶の1行目に(符号付)整数で表示すること。
・ A/D変換された値を符号なし整数で受け取り液晶の2行目に符号なし整数として表示すること
・ A/D変換された8ビット値を LSB(第0位ビット)→RB0、第1位ビット→RB1、…… MSB(第7位ビット)→RB7、
となるように対応させ、A/Dコンバータの値にしたがってLEDを点滅させること
・ 入力電圧が0Vの時LEDはすべてOFF、5Vの時はすべて点灯させること
<試作品回路図>
PIC16F877をつかった場合の回路図を以下に示します。(→回路図のPDFファイル)
<プログラム例> /* ------------------------------------------------------------------ PIC16F877 ADコンバータの値を整数と符号なし整数の両方で呼んで液晶に比較表示する 内臓ADコンバータを8ビットの分解能で使ってアナログ電圧を読み込み値を8個のLEDで表示する -------------------------------------------------------------------- */ #include "16f877.h" #device ADC=8 #use delay(clock=20000000) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #byte port_b=6 //Bポートレジスタ(6番地)を 変数port_bに対応させる #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> main(){ int intX; unsigned int unsignedintX; set_tris_b(0); setup_adc_ports(ALL_ANALOG); //AN0〜AN7すべてをA/D変換入力ポートに設定 setup_adc(ADC_CLOCK_INTERNAL); //逐次変換して比較する時、内部クロックを使用する lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); delay_ms(2000); lcd_clear(); while(1) { set_adc_channel(0); // チャンネルAN0のADコンバータ変換開始 delay_us(50); //A/D変換されたデジタル値がセットされるまでの時間(トータルセトリング時間)+αの時間だけ待ちます intX = read_adc(); //A/D変換された値を読み込み、整数の変数にセットします unsignedintX = read_adc(); //A/D変換された値を読み込み、符号なし整数の変数にセットします lcd_clear();// 液晶オールクリア printf(lcd_data,"intX=%d",intX);//読み込んだ値を lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"unsignedintX=%u",unsignedintX); port_b = ~(unsignedintX); //BポートにAD変換されたデジタル値を出力する delay_ms(300); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
入力電圧が2.5V以下の場合 整数 と 符号なし整数は同じ値となる |
入力電圧が2.5v以上の場合 整数と符号なし整数は異なる値となる |
|
<試作品仕様>
・ 可変抵抗器で0〜5Vの電圧をつくり、ポートAN0に入力すること
・ AN0に入力された電圧を電源変動、温度変動の少ない比較基準電圧をもちいて10ビットのA/Dコンバータで
読み込むこと
・ A/D変換されたデジタル変換値を液晶の1行目に10進数で表示すること。
・ また液晶の2行目には入力された電圧を 単位 V で表示すること
<試作品回路図> (→回路図のPDFファイル)
PIC16F877をつかった場合の回路図を以下に示します。 安定した基準電圧素子としてナショゼミのLM385を
つかった例を以下に示します。下図の場合RA3に入力される基準電圧はデータシートにある計算式より
Vref = 1.24 ×(R3/R2 + 1) = 1.24 × ( 220kΩ/100KΩ + 1 )
= 3.968 V
となります。
<プログラム例>
/* ------------------------------------------------------------------ PIC16F877 ADコンバータの値を符号なし整数で読み込んで 10ビット値と電圧値を液晶に比較表示する 基準電圧はLM385で安定化された3.968Vを使用する -------------------------------------------------------------------- */ #include "16f877.h" #device ADC=10 #use delay(clock=20000000) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #byte port_b=6 //Bポートレジスタ(6番地)を 変数port_bに対応させる #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> main(){ unsigned long int adValue; set_tris_b(0); setup_adc_ports(AN0_AN1_VSS_VREF); //AN0 AN1をAN3に入力される電圧を基準にA/D変換ポートに設定 setup_adc(ADC_CLOCK_INTERNAL); //逐次変換して比較する時、内部クロックを使用する lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); delay_ms(2000); lcd_clear(); while(1) { set_adc_channel(0); // チャンネルAN0のADコンバータ変換開始 delay_us(50); //A/D変換されたデジタル値がセットされるまでの時間(トータルセトリング時間)+αの時間だけ待ちます adValue = read_adc(); //A/D変換された値を読み込み、符号なし整数の変数にセットします lcd_clear();// 液晶オールクリア printf(lcd_data,"adValue=%lu",adValue);//読み込んだ値を lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Vin=%4.3f V",3.968*((float)AdValue/1023)); //10ビット値を電圧値に換算 delay_ms(300); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
<試作品回路図>PIC18F87K90をつかった場合の回路図を以下に示します。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /* AD コンバータ 12ビットAD PC18F87K90 */ #include <p18f87K90.h> #include <stdio.h> #include <delays.h> #include <timers.h> #include <adc.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config FOSC = XT //FOSC = HS // システムクロック=1MHz #pragma config XINST = OFF #pragma config WDTEN = OFF //ウォッドックタイマ OFF unsigned int Count_10msec; char tempBuf[17]; //液晶表示データの一時保存レジスタ long int ADread; char str[17]; char str2[30]; float Vin,Vin1000; long int Vin1000i; int Vi,Vf; void delay_ms (long int cycle) // CCSコンパイラと同じ delay_ms(long int) 関数を設計 { long int i = 0; for (i = 0; i < cycle; i++)Delay10TCYx(25); // 25 x 40μsec = 1000μsec // Delay10TCY():40μsec } void lcd_printf(char* str) //液晶表示補助関数 { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } } void Ad_Func() //AD変換読込み & 表示 { SetChanADC(ADC_CH0); //チャンネルを切り替える場合 ConvertADC(); while( BusyADC()); //AD変換が終わるまで待つ ADread = ReadADC(); //AD変換値読込み //液晶へ表示 lcd_clear(); sprintf(str,"ADread=%ld",ADread); lcd_printf(&str[0]);// AD変換読込み値を液晶に1行目に表示 読込み値:1023(at 5V) Vin = (float)ADread/4095*5.0; Vi = (int)Vin; Vf =(int)( (Vin - (int)Vin)*100); sprintf(&str2[0],"Vin[v]=%d.%d",Vi,Vf); // %f(浮動少数)は未サポート lcd_cmd(0xC0);//2行目の先頭へ lcd_printf(&str2[0]);// AD変換読込み値を液晶に2行目に表示 読込み値:1023(at 5V) } #pragma interrupt my_Func // 10msec タイマ1 インターバル割り込み #pragma code isrcode = 0x08 void isr_direct(void) { _asm goto my_Func _endasm } #pragma code void my_Func(void) { LATJbits.LATJ0 = 0; PIR1bits.TMR1IF = 0; // タイマ1割り込みフラグをクリアする WriteTimer1(15536); // 1μsec × 4 × 1 × 50000 = 200000μsec = 200msec (at システムクロック1MHz) // 256×256 - 50000 = 15536 Ad_Func(); LATJbits.LATJ0 = 1; } void main (void) { unsigned char channel=0x00,config1=0x00,config2=0x00,config3=0x00,portconfig=0x00; TRISD = 0; TRISJ = 0; TRISAbits.TRISA0 = 1; TRISAbits.TRISA2 = 1; TRISAbits.TRISA3 = 1; ANCON0 = 0b00001101; //RA0 ANCON1 = 0; ANCON2 = 0; config1 = //ADCON0: A/D CONTROL REGISTER 0 ADC_CH0 | //AD変換するのチャンネル選択(PIC18Fは同時に複数のAD変換はできない) ADC_INT_OFF | //AD変換での割込み使用の有無 ADC_REF_VDD_INT_VREF_2 | // ADC_REF_VDD_VREFPLUS | //Vref+の設定 外部Vref電圧 ADC_REF_VDD_VSS ; //Vref-の設定 PICの0V //ADCON1: A/D CONTROL REGISTER 1 config2 = //ADCON2: A/D CONTROL REGISTER 2 ADC_FOSC_2 | //AD変換用クロック システムクロックの1/2 ADC_RIGHT_JUST | //変換結果の保存方法 左詰め ADC_2_TAD ; //AD変換のアクイジションタイム選択 変換クロック時間(=1Tad)×2Tad OpenADC(config1,config2,portconfig); //ADCON1レジスタ// 電源電圧リファレンスでない場合はADCON1レジスタの書き込みが必要である。 C18のバグ? ADCON1bits.TRIGSEL1 = 0; // ADCON1bits.TRIGSEL0 = 0; ADCON1bits.VCFG1 = 0; //01: 外部リファレンス//(参考:10: Vref = 2.048v) ADCON1bits.VCFG0 = 1; ADCON1bits.VNCFG = 0; //Vref-: AVss //PICのGND // ★内部リファレンス 及び外部リファレンス共に Vref- を0Vに接続する必要なし // ★差動入力の場合のみ必要 // ★電源電圧がリファレンス電圧以下になると まったくおかしなAD変換値となる。 ADCON1bits.CHSN2 = 0; //Vref- としてAVss と外部Vref-を選択した場合は000を選択 ADCON1bits.CHSN1 = 0; ADCON1bits.CHSN0 = 0; lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); sprintf(&tempBuf[0],"AD Converter !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); lcd_cmd(0xC0);//2行目の先頭へ sprintf(&tempBuf[0]," Start2 !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); while (1) { Ad_Func(); delay_ms(200); } } //************************************************ //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //************************************************ #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD3 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag); //*********************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //*********************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<実行結果>
・リファレンス電圧が電源電圧以下の場合は 妥当な実験結果がえられた。 すなわち 電源電圧がリファレンス電圧2.4V以下になると まったくおかしなAD変換値となる
・外部リファレンス電圧でのAD変換の場合、 Vref- 端子は GNDに接続する必要はない。 ソフトでの設定だけでよい。
・リファレンス電圧の出力インピーダンスは低くなければならない。
・電圧測定端子に直接基準電圧素子LM285-1.2をつないでもAN端子の入力インピーダンスが高いので基準電圧降下は得られなかった。 20KΩのダミー抵抗を接続すると1.2vの電圧降下は得られる。
・PIC電圧が低下した時の液晶(+5.0V)との信号電圧レベル変換レベルシフターとして、 3.0v電源の74HC4050は有効であった。
AD変換値 | 理論値 | |||||||
被測定電圧\PIC電源電圧 | 1.6v | 1.8v | 2.0v | 2.5v | 3.0v | 3.3v | 5.0v | |
0.5v | 3793 | 3860 | 3888 | 845 | 810 | 810 | 880 | 4095 × 0.5/2.4 = 853 |
1.0v | 3807 | 3883 | 3916 | 1653 | 1668 | 1681 | 1700 | 4095 × 10/2.4 = 1706 |
1.8v | 3825 | 3900 | 3944 | 2948 | 2971 | 2950 | 2953 | 4095 × 1.8/2.4 = 3071 |
(4) A/D変換を2つ使用した高分解能10ビットA/D変換
<試作品仕様>
・ 可変抵抗器で0〜5Vの電圧をつくり、ポートAN0に入力すること
・ 測定電圧が小さな値においてもの相対的にA/Dの分解能を高めること
・ AN0、AN1でA/D変換されたデジタル変換値を液晶の1行目に10進数で表示すること。
・ 液晶の2行目には AD変換された10ビット値と入力された電圧をボルト(小数点以下3桁)で表示すること
<試作品回路図> (→回路図のPDFファイル)
PIC16F877をつかった場合の回路図を以下に示します。単電源で特性のよいオペアンプLM2904をもちいて10倍の
アンプをつくり測定電圧を増幅してこの出力をAN1に接続しました。 LM2904を+5Vの単電源で使用する場合リニア
リティがよいのは出力が3.5V程度までなので 出力電圧で0〜2.5Vの範囲のAN1入力電圧を活用することとしました。
こうすることで測定電圧の0〜0.25Vが高分解能でA/D変換できることになります。
<プログラム例>
/* ------------------------------------------------------------------ PIC16F877 小さな値はアナログアンプ(ゲイン=10倍)で増幅後AD変換してよむ ADコンバータを2つ使い小さな電圧検出の分解能をあげる -------------------------------------------------------------------- */ #include "16f877.h" #device ADC=10 #use delay(clock=20000000) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #byte port_b=6 //Bポートレジスタ(6番地)を 変数port_bに対応させる #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> main(){ unsigned long int A0,A1,AT; set_tris_b(0); setup_adc_ports(ALL_ANALOG); //AN0 AN1をAN3に入力される電圧を基準にA/D変換ポートに設定 setup_adc(ADC_CLOCK_INTERNAL); //逐次変換して比較する時、内部クロックを使用する lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); delay_ms(2000); lcd_clear(); while(1) { set_adc_channel(0); // チャンネルAN0のADコンバータ変換開始 delay_us(50); //A/D変換されたデジタル値がセットされるまでの時間(トータルセトリング時間)+αの時間だけ待ちます A0 = read_adc(); //A/D変換された値を読み込み、符号なし整数の変数にセットします set_adc_channel(1); // チャンネルAN1のADコンバータ変換開始 delay_us(50); //A/D変換されたデジタル値がセットされるまでの時間(トータルセトリング時間)+αの時間だけ待ちます A1 = read_adc(); //A/D変換された値を読み込み、符号なし整数の変数にセットします lcd_clear();// 液晶オールクリア printf(lcd_data,"A0=%lu A1=%lu",A0,A1);//読み込んだ値を表示 if(A0>= 52) { AT = A0; //5%以上ならA0から読み込んだ値をつかう 1023 × 0.05 = 51.15 //5V×0.05 = 0.25V 0.25V × 10(=アンプゲイン) = 2.5V // 2.5V < 3.5V(アンプ飽和電圧) lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"AT=%lu V=%4.3f",AT,5*((float)AT/1023)); //10ビット値を電圧値に換算 } else { AT = A1; lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"AT=%lu V=%4.3fV",AT,5*((float)AT/1023/10)); //10ビット値を電圧値に換算 } delay_ms(300); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
A0(=18)がアンプ(ゲイン10倍)を経ない電圧をよんだA/D変換の10ビット値で、A1(=175)がアンプ(ゲイン10倍)を
経た後によんだA/D変換の10ビット値です。分解能が1桁あがっていることがわかります。
アナログのアンプを追加して2つのA/DコンバータでA/D変換をおこなうことは、小さな値の測定値に対しても相対的
精度を要求される場合に有効な方法だと思います。12ビット、16ビットのA/Dコンバータを外付けするとPICとのインター
フェース、処理スピード、コスト等いろいろな問題が発生してきます。
■ C18コンパイラ
C18コンパイラの場合、内臓ADコンバータからのAD変換値を読込みの基本的な流れは以下のようになります。
@ OpenADC() 関数で SFRの設定をおこなう。但し一部のPICでは直接のレジスタ書き込みも必要となる。
A SetChanADC()関数で 読み込みのチャンネルを選択する。
B ConvertADC()関数で 読み込みを開始する。
C BusyADC()関数で AD変換が完了するのを待つ(戻り値が"0"になるまで待つ)
D ReadADC()関数で AD変換値を読み込む
E CloseADC()関数で AD変換をDisableにする
(1)入力電圧を液晶に表示(PIC18F4550)
PIC18F4550の内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。 PICの種類によって
OpenADC()関数の引数、及び引数の数が異なります。PIC18F4550の場合はSFRのADCON0、ADCON1、ADCON2レジスタ
すべての設定がOpenADC()関数の引数でおこなわれます。
<試作品仕様>
・ PIC18F4550のAN0端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+5V(PICの電源電圧)とする。
・ 液晶には以下を200msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
<試作品回路図>
PIC18F4550の場合の回路図を以下にしめします。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /* C18コンパイラ PIC18F4550 内臓AD変換回路読込み */ #include <p18f4550.h> #include <adc.h> #include <delays.h> #include <stdio.h> #include <stdlib.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config PLLDIV = 5 //96MHz PLL Prescalar(1、2、3、4、5、6、10、12のみ) : 外部周波数÷4MHz //20MHz ÷ 5 = 4MHz → 96MHz(=4MHz×24 :固定) #pragma config USBDIV = 2 // Full Speed USB Clock Source Selection : 2(constant) #pragma config CPUDIV = OSC1_PLL2 //CPU System Clock Postscaler // PICのシステムクロック周波数:48MHz(=96MHz ÷2) #pragma config FOSC = HS // システムクロック=20MHz //#pragma config FOSC = HSPLL_HS // システムクロック=48MHz #pragma config WDT = OFF #pragma config LVP = OFF void lcd_printf(char* str) //液晶表示補助関数 { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } } void Ad_Func() //AD変換読込み & 表示 { int ADread; char str[17]; char str2[30]; float Vin,Vin1000; long int Vin1000i; int Vi,Vf; // SetChanADC(ADC_CH1); //チャンネルを切り替える場合 ConvertADC(); while( BusyADC()); //AD変換が終わるまで待つ ADread = ReadADC(); //AD変換値読込み //液晶へ表示 lcd_clear(); sprintf(str,"ADread=%d",ADread); lcd_printf(&str[0]);// AD変換読込み値を液晶に1行目に表示 読込み値:1023(at 5V) Vin = (float)ADread/1023*5; Vi = (int)Vin; Vf =(int)( (Vin - (int)Vin)*100); sprintf(&str2[0],"Vin[v]=%d.%d",Vi,Vf); // %f(浮動少数)は未サポート lcd_cmd(0xC0);//2行目の先頭へ lcd_printf(&str2[0]);// AD変換読込み値を液晶に2行目に表示 読込み値:1023(at 5V) Delay10KTCYx(100); //200msec 毎に読込み // 10KT:0.05μsec×4×10000=2000μsec=2msec } void main (void) { char tempBuf[17]; //液晶表示データの一時保存レジスタ OpenADC(ADC_FOSC_64 & //AD変換用クロック システムクロックの1/64 0.05μsec×64=3.2μsec >= 1.6μsec → OK ADC_RIGHT_JUST & //変換結果の保存方法 左詰め ADC_8_TAD, //AD変換のアクイジションタイム選択 3.2μsec(=1Tad)×8Tad=25.6μsec >= 12.8μsec → OK ADC_CH0 & //AD変換するのチャンネル選択(PIC18Fは同時に複数のAD変換はできない) ADC_INT_OFF & //AD変換での割込み使用の有無 ADC_VREFPLUS_VDD & //Vref+の設定 PICの電源電圧と同じ:ADC_VREFPLUS_VDD or 外部(AN3)の電圧:ADC_VREFPLUS_EXT ADC_VREFMINUS_VSS, //Vref-の設定 PICの0V:ADC_VREFMINUS_VSS or 外部(AN2)の電圧:ADC_VREFMINUS_EXT 0b1110 //ポートのアナログ・デジタル選択 (ADCON1の下位4ビットを記載) AN0のみアナログポートを選択、他はデジタルポートを選択 //例 アナログポートが AN0のみ → 0b1110 、AN0 & AN1 → 0b1011、 AN0 & AN1 & AN2 →1100 他 詳細データシート参照 ); Delay10KTCYx(25);//50msec液晶立ち上がりを待つ 10KT:0.05μsec×4×10000=2000μsec=2msec lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); sprintf(&tempBuf[0],"AD Converter !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); lcd_cmd(0xC0);//2行目の先頭へ sprintf(&tempBuf[0]," Start2 !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); while (1) { Ad_Func(); } CloseADC(); } //************************************************************************* //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ //1lcd_lib.cをC18コンパイラ用に変更したものです。 //************************************************************************* #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD0 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag); //************************************************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ //1lcd_lib.cをC18コンパイラ用に変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<動作結果>
AN0端子の入力電圧(デジタルテスタ表示値)が 概略 0v、 2.5v、 5.0vの時の液晶表示を以下に示します。
AN0端子入力電圧 | ||||
0v | 2.5v | 5.0v | ||
(2)入力電圧を液晶に表示(PIC18F452)
PIC18F452の内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。 PICの種類によって
OpenADC()関数の引数、及び引数の数が異なります。PIC18F452の場合は一部の設定がOpenADC()関数の引数では
設定されない為、レジスタに直接書き込む必要があります。具体的には、端子の属性(アナログポート、デジタルポート、
+Vref、 -Vref )を設定するためにADCON2レジスタの下位4ビットに直接書き込みます。
<試作品仕様>
・ PIC18F452のAN0端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+5V(PICの電源電圧)とする。
・ 液晶には以下を200msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
<試作品回路図>PIC18F452をつかった場合の回路図を以下に示します。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /* C18コンパイラ PIC18F452 内臓AD変換回路読込み */ #include <p18f452.h> #include <adc.h> #include <delays.h> #include <stdio.h> #include <stdlib.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config OSC = HSPLL // f = 40MHz ( = 10MHz × 4(PLL)) #pragma config WDT = OFF #pragma config LVP = OFF void lcd_printf(char* str) //液晶表示補助関数 { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } } void Ad_Func() //AD変換読込み & 表示 { int ADread; char str[17]; char str2[30]; float Vin,Vin1000; long int Vin1000i; int Vi,Vf; // SetChanADC(ADC_CH1); //チャンネルを切り替える場合 ConvertADC(); while( BusyADC()); //AD変換が終わるまで待つ ADread = ReadADC(); //AD変換値読込み //液晶へ表示 lcd_clear(); sprintf(str,"ADread=%d",ADread); lcd_printf(&str[0]);// AD変換読込み値を液晶に1行目に表示 読込み値:1023(at 5V) Vin = (float)ADread/1023*5; Vi = (int)Vin; Vf =(int)( (Vin - (int)Vin)*100); sprintf(&str2[0],"Vin[v]=%d.%d",Vi,Vf); // %f(浮動少数)は未サポート lcd_cmd(0xC0);//2行目の先頭へ lcd_printf(&str2[0]);// AD変換読込み値を液晶に2行目に表示 読込み値:1023(at 5V) Delay10KTCYx(100); //200msec 毎に読込み // 10KT:0.05μsec×4×10000=2000μsec=2msec } void main (void) { char tempBuf[17]; //液晶表示データの一時保存レジスタ OpenADC(ADC_FOSC_64 & //AD変換用クロック システムクロックの1/64 0.05μsec×64=3.2μsec >= 1.6μsec → OK ADC_RIGHT_JUST & //変換結果の保存方法 左詰め ADC_1ANA_0REF, //AD変換のアクイジションタイム選択 3.2μsec(=1Tad)×8Tad=25.6μsec >= 12.8μsec → OK ADC_CH0 & //AD変換するのチャンネル選択(PIC18Fは同時に複数のAD変換はできない) ADC_INT_OFF //AD変換での割込み使用の有無 ); ADCON1 = (ADCON1 & 0xF0) | 0b00001110; //0b1110 → アナログ端子RA0のみ +Vref=Vdd -Vrerf=GND // ADCON1の下位4ビットで端子の属性を指定する → アナログ端子、デジタル端子、+Vref端子、-Vref端子 //例 0b1111 → RA0のみアナログ端子、+Vref端子=RA3、-Vref=RA2 // 0b0100 → RA0、RA1,RA3アナログ端子 +Vref=Vdd -Vrerf=GND 他 詳細18F452のデータシート参照 Delay10KTCYx(25);//50msec液晶立ち上がりを待つ 10KT:0.05μsec×4×10000=2000μsec=2msec lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); sprintf(&tempBuf[0],"AD Converter !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); lcd_cmd(0xC0);//2行目の先頭へ sprintf(&tempBuf[0]," Start2 !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); while (1) { Ad_Func(); } CloseADC(); } //************************************************************************* //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ //1lcd_lib.cをC18コンパイラ用に変更したものです。 //************************************************************************* #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD0 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag); //************************************************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ //1lcd_lib.cをC18コンパイラ用に変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<動作結果>
入力電圧が2.5vの場合の写真を以下に示します。
(3)入力電圧を液晶に表示(PIC18F87K90)
<試作品回路図>PIC18F87K90をつかった場合の回路図を以下に示します。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /* AD コンバータ 12ビットAD PC18F87K90 */ #include <p18f87K90.h> #include <stdio.h> #include <delays.h> #include <timers.h> #include <adc.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config FOSC = XT //FOSC = HS // システムクロック=1MHz #pragma config XINST = OFF #pragma config WDTEN = OFF //ウォッドックタイマ OFF unsigned int Count_10msec; char tempBuf[17]; //液晶表示データの一時保存レジスタ long int ADread; char str[17]; char str2[30]; float Vin,Vin1000; long int Vin1000i; int Vi,Vf; void delay_ms (long int cycle) // CCSコンパイラと同じ delay_ms(long int) 関数を設計 { long int i = 0; for (i = 0; i < cycle; i++)Delay10TCYx(25); // 25 x 40μsec = 1000μsec // Delay10TCY():40μsec } void lcd_printf(char* str) //液晶表示補助関数 { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } } void Ad_Func() //AD変換読込み & 表示 { SetChanADC(ADC_CH0); //チャンネルを切り替える場合 ConvertADC(); while( BusyADC()); //AD変換が終わるまで待つ ADread = ReadADC(); //AD変換値読込み //液晶へ表示 lcd_clear(); sprintf(str,"ADread=%ld",ADread); lcd_printf(&str[0]);// AD変換読込み値を液晶に1行目に表示 読込み値:1023(at 5V) Vin = (float)ADread/4095*3.3; Vi = (int)Vin; Vf =(int)( (Vin - (int)Vin)*100); sprintf(&str2[0],"Vin[v]=%d.%d",Vi,Vf); // %f(浮動少数)は未サポート lcd_cmd(0xC0);//2行目の先頭へ lcd_printf(&str2[0]);// AD変換読込み値を液晶に2行目に表示 読込み値:1023(at 5V) } #pragma interrupt my_Func // 10msec タイマ1 インターバル割り込み #pragma code isrcode = 0x08 void isr_direct(void) { _asm goto my_Func _endasm } #pragma code void my_Func(void) { LATJbits.LATJ0 = 0; PIR1bits.TMR1IF = 0; // タイマ1割り込みフラグをクリアする WriteTimer1(15536); // 1μsec × 4 × 1 × 50000 = 200000μsec = 200msec (at システムクロック1MHz) // 256×256 - 50000 = 15536 Ad_Func(); LATJbits.LATJ0 = 1; } void main (void) { unsigned char channel=0x00,config1=0x00,config2=0x00,config3=0x00,portconfig=0x00; TRISD = 0; TRISJ = 0; TRISAbits.TRISA0 = 1; TRISAbits.TRISA3 = 1; ANCON0 = 0b00001001; //RA0 ANCON1 = 0; ANCON2 = 0; config1 = //ADCON0: A/D CONTROL REGISTER 0 ADC_CH0 | //AD変換するのチャンネル選択(PIC18Fは同時に複数のAD変換はできない) ADC_INT_OFF | //AD変換での割込み使用の有無 ADC_REF_VDD_VDD | //Vref+の設定 PICのVcc ADC_REF_VDD_VSS ; //Vref-の設定 PICの0V //ADCON1: A/D CONTROL REGISTER 1 config2 = //ADCON2: A/D CONTROL REGISTER 2 ADC_FOSC_2 | //AD変換用クロック システムクロックの1/2 ADC_RIGHT_JUST | //変換結果の保存方法 左詰め ADC_2_TAD ; //AD変換のアクイジションタイム選択 変換クロック時間(=1Tad)×2Tad OpenADC(config1,config2,portconfig); lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); sprintf(&tempBuf[0],"AD Converter !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); lcd_cmd(0xC0);//2行目の先頭へ sprintf(&tempBuf[0]," Start2 !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); while (1) { Ad_Func(); delay_ms(200); } } //************************************************ //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //************************************************ #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD3 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag); //*********************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //*********************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
■ XC8 コンパイラ編
<試作品回路図> PIC18F14K50をつかった場合の回路図を以下に示します。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //AD コンバータ // チャンネルAN8(RC6) #include <p18f14K50.h> #include <xc.h> #include <stdio.h> #include <stdarg.h> #include "lcd_lib_XC8.h" #define _XTAL_FREQ 48000000 //PLL ON Periferal= 12MHz x 4 = 48MHz #pragma config CPUDIV = NOCLKDIV ,USBDIV = OFF,PCLKEN = ON #pragma config FOSC = HS,PLLEN = ON, HFOFST = OFF //PLL ON Periferal= 12MHz x 4 = 48MHz #pragma config PWRTEN = ON, BOREN = OFF, MCLRE = OFF, BORV = 30 #pragma config WDTEN = OFF,LVP = OFF,FCMEN = OFF, IESO = OFF #pragma config CP0 = OFF,XINST = OFF #pragma config STVREN = OFF, BBSIZ = OFF,CPB = OFF,CP1 = OFF,CPD = OFF //省略するとwarnig がでる #pragma config WRT0 = OFF,WRT1 = OFF,WRTC = OFF,WRTB = OFF,EBTR0 = OFF,EBTR1 = OFF,EBTRB = OFF //省略するとwarnig がでる char Buf[17]; //液晶表示データの一時保存レジスタ int Mode = 0; int ADread; float Vin,Vin1000; long int Vin1000i; int Vi,Vf; void delay_ms(unsigned short msec) //1msec遅延関数 { unsigned short i; for(i=0; i<msec; i++) __delay_ms(1); // __delay_ms(n); //n = 1?16 // __delay_us(1); //__delay_us(n); //n = 1?16426 //1μsec遅延関数 } void lcd_printf(char* str) //液晶表示補助関数 { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } } void AdFunc(void) { char* pStr; ADCON0 = 0b00100001; //AN8(RC6)選択、ADコンバータ有効化 ADCON0bits.GO = 1; // AD変換開始 while (ADCON0bits.GO); // AD変換完了待ち ADread = ADRESL+(ADRESH*256); // 10bitの値に変換 //液晶へ表示 lcd_clear(); pStr = &Buf[0]; sprintf(pStr,"ADread=%d",ADread); lcd_printf(pStr);// AD変換読込み値を液晶に1行目に表示 読込み値:1023(at 5V) Vin = (float)ADread/1023*5; Vi = (int)Vin; Vf =(int)( (Vin - (int)Vin)*100); sprintf(pStr,"Vin[v]=%d.%d",Vi,Vf); // %f(浮動少数)は未サポート lcd_cmd(0xC0);//2行目の先頭へ lcd_printf(pStr);// AD変換読込み値を液晶に2行目に表示 読込み値:1023(at 5V) } int main() { char* pStr; ANSEL = 0x00; // デジタルに設定 ANSEL = 0x00; // デジタルに設定 ANSELH =0b00000011; // RC6(AN8),RC7(AM9)のみアナログ // ADC初期化 // ADCON0 = 0; // 停止 ADCON0bits.ADON = 0; //ADC: Disable // ADCON1 = 0; // VDD-Vss ADCON1bits.PVCFG0 = 0; // Vref+ = Vdd //Positive Voltage Reference select bit ADCON1bits.PVCFG1 = 0; // ADCON1bits.NVCFG0 = 0; //Vref- = GND //Negative Voltage Reference select bit ADCON1bits.NVCFG1 = 0; // ADCON2 = 0xBE; // 右詰め,20Tad,Fosc/64 ADCON2bits.ADFM = 1; //右詰め ADCON2bits.ADCS0 = 0; //110: FOSC/64 //AD変換用クロック選択 //A/D Conversion Clock Select bits ADCON2bits.ADCS1 = 1; ADCON2bits.ADCS2 = 1; ADCON2bits.ACQT0 = 1; //20TAD; //TAD(AD変換用クロック周期)×20 //アクイジションタイム(充電時間) ///A/D Acquisition time select bits. Acquisition time is the duration that the A/D charge ADCON2bits.ACQT1 = 1; //holding capacitor remains connected to A/D channel from the instant the GO/DONE bit is ADCON2bits.ACQT2 = 1; //set until conversions begins. TRISC = 0b11000000; TRISB = 0; lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); pStr = &Buf[0]; lcd_cmd(0x80); //1行目の先頭へ sprintf(pStr,"XC8"); //文字列としてバッファーに収納 lcd_printf(pStr); lcd_cmd(0xC0);//2行目の先頭へ sprintf(pStr," A/D Start !!"); //文字列としてバッファーに収納 lcd_printf(pStr); delay_ms(2000); while(1) { AdFunc(); delay_ms(500); } return 0; } //************************************************ //インクルードファイル lcd_lib_XC8.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //XC8コンパイラ用に変更したものです。 //************************************************ // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB7 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB6 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB5 //LCDのDB5 (12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB4 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATCbits.LATC5 //stb OutPort #define lcd_rs LATCbits.LATC4 // rs OutPort void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag); //*********************************************** //インクルードファイル lcd_lib_XC8.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //XC8コンパイラ用に変更したものです。 //*********************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "lcd_lib_XC8.h" #include <p18f14K50.h> #include <stdio.h> #include <stdlib.h> #define _XTAL_FREQ 48000000 //////// データ出力サブ関数 void lcd_out(char code, char flag) { //port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; //lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 _delay(10); //Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out _delay(10); //Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 _delay(500); //Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) __delay_ms(2); //Delay10KTCYx(2); //2msec待ち at 40MHz else __delay_us(50); //Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set __delay_ms(5); //Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set __delay_ms(1); //Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set __delay_ms(1); //Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set __delay_ms(1); //Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<動作結果>
入力電圧 | 液晶表示 |
0V | |
2.5V | |
5.0V |
■ C30コンパイラ dsPIC編
C30コンパイラの場合、内臓ADコンバータからの12bitAD変換値読込みの基本的な流れは以下のようになります。
@ OpenADC12() 関数で SFRの設定をおこなう。
A SetChanADC12()関数で 読み込みのチャンネルを選択する。
B ConvertADC12()関数で 読み込みを開始する。 (注1)( ADCON1bits.SAMP =1; )
C BusyADC12()関数で AD変換が完了するのを待つ (注1)( while(!ADCON1bits.DONE); )
D ReadADC12()関数で AD変換値を読み込む (注1)(AdcValue = ADCBUF0;)
E CloseADC12()関数で AD変換をDisableにする
(注1)( )内のように直接レジスタにアクセスした方が速いようです。
(注2)10ビット用の関数は関数の末尾12が10となります。
(1)入力電圧を液晶に表示(dsPIC30F2012)
dsPIC30F2012の内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。書き込みはICSPを
使っています。
<試作品仕様>
・ dsPIC30F2012のAN3端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+5V(PICの電源電圧)とする。
・ 液晶には以下を200msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
<試作品回路図>
dsPIC30F2012の場合の回路図を以下にしめします。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> ///************************************************************/ //* AD変換 液晶表示 //* dsPIC30F2012 //************************************************************/ // MPLAB プロジェクトへの追加ファイル // Linker Scriptフォルダ p30f2012.gld // Library Filesフォルダ lib30F2012-coff.a #include "p30f2012.h" #include <stdio.h> #include <adc12.h> #include <timer.h> #include "1lcd_lib_C30.h" _FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェールセイフクロックモニタなし FRC_PLL16 //内臓高速RC発振器(7.37MHz)、PLL:16倍 → システムクロック周波数=7.37×16=117.92MHz ); _FWDT(WDT_OFF); _FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON BORV_42 & //ブラウンアウト電圧:4.2V PWRT_64 & //パワーオンリセットタイマ64msec MCLR_EN //MCLR機能:ON ); _FGS(CODE_PROT_OFF); //コードプロテクト:OFF unsigned int Config1 = //ADCON1レジスタの設定 ADC_MODULE_ON & //ADON bit15=1 : ADコンバータモジュール → ON //AD Module On/Off ADC_IDLE_CONTINUE & //ADSIL bit13=0 : アイドル時の動作 → 動作継続 //Idle Mode Operation ADC_FORMAT_INTG & //FORM bit9-8=00 :出力データのフォーマット → 整数 //Result Output Format ADC_CLK_AUTO & //SSRC bit5-7=111 :変換開始トリガ設定 //Conversion Trigger Source // →ADCON3のSAMCによるクロック(サンプルホールド)が終了後変換自動開始 ADC_AUTO_SAMPLING_OFF & //ASAM bit2=1 : ADサンプリング自動開始→手動開始 //Auto Sampling Select ADC_SAMP_OFF; //SAMP bit1=0 : サンプリング手動制御→OFF //Sample Enable // (例)ASAM = 0(ADC_AUTO_SAMPLING_OFF) の時 SAMP=1(ADC_SAMP_ON)で変換開始 //DONE bit0 : AD変換終了フラグ(AD変換が終了すると1が立つ、 書き込み不可) unsigned int Config2 = //ADCON2レジスタの設定 ADC_VREF_AVDD_AVSS & //VCFG bit13-15=000: S/Hアンプのリファレンス設定: 基準電圧Vdd、シングルエンド //Voltage Reference ADC_SCAN_OFF & //CSCNA bit10=0 : MUX交互自動スキャン制御→オフ //Scan Section ADC_SAMPLES_PER_INT_1 & //SMPI bit2-5 : 割込み頻度→1回毎 //Number of Samples between Interrupts ADC_ALT_BUF_OFF & //BUFM bit1=0: 交互バッファー制御→なし //Buffer mode Select ADC_ALT_INPUT_OFF; //ALTS bit0=0: AD入力の複数バッファーへの格納//Alternate Input sample Mode Select( unsigned int Config3 = //ADCON3レジスタの設定 ADC_SAMPLE_TIME_10 & //SAMC bit8-12 :サンプルホールド時間 → 10サイクル(TAD)//Auto Sample Time bits ADC_CONV_CLK_SYSTEM & //ADRC bit7=0 :AD変換クロック→システムクロック //Conversion Clock Source Select ADC_CONV_CLK_32Tcy; //ADCS bit0-5 :変換クロック数→32Tcy(設定のMAXを選択) //Conversion Clock Select unsigned int ConfigPort = //ADPCFGレジスタの設定 ANLOG/DIGITAl Pin Select //ex1. ENABLE_ALL_ANA ex2. ENABLE_ALL_DIG ex3. ENABLE_AN0_ANA & ENABLE_AN1_ANA ENABLE_AN3_ANA; //AN1 → アナログポート unsigned int ConfigScan = //ADCSSLレジスタの設定 Scan Channel Select SCAN_NONE; //ADCSLL = 0x0000 : 自動スキャン→スキャンせず unsigned int Channel1 = //ADCHSレジスタの設定 ADC_CH0_POS_SAMPLEA_AN3 & //マルチプレクサA(S/Hアンプ)のVref+への接続チャンネル → チャンネル1 ADC_CH0_NEG_SAMPLEA_NVREF; //マルチプレクサA(S/Hアンプ)のVref-への接続チャンネル → Vss void AdcFunc(void); void delay_ms(unsigned int); unsigned int Count=0; unsigned int AdcValue; char Buf[17]; //文字列のバッファー用レジスタ void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/4000*N); } void AdcFunc(void) // AD変換読み取り & 液晶表示 { float Volt; unsigned int I; unsigned int F; SetChanADC12(Channel1); //Vref-(RB1、AN1) → GND ADCON1bits.SAMP =1; //サンプリング開始 //サンプルホールド時間:8TAD (ADCON3のSAMC<3:0>) //変換の自動開始 //変換時間:31TAD (ADCON3のADCS<5:0>) // while(BusyADC12()); while(!ADCON1bits.DONE); //AD変換終了フラグが1になるまでまつ // AdcValue = ReadADC12(0); //AD変換値読込み(読込みが遅い) AdcValue = ADCBUF0; //AD変換値読込み(レジスタ直読 → 読込みが早い) Count++; lcd_clear(); //全消去 sprintf(Buf,"AdV=%u",AdcValue); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 Volt =(float)AdcValue/4095*5; I = (unsigned int) Volt; F = (unsigned int)(( Volt - I)*1000); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"Volt=%u.%u[V]",I,F); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 } void _ISR _T1Interrupt(void) //タイマ1割込み { IFS0bits.T1IF = 0; //フラグクリア AdcFunc(); // AD変換読み取り & 液晶表示 } /// メイン関数 int main(void) { TRISB = 0b0000000000001000; // AD入力のbit3(AN3 RB3)のみ入力 TRISF = 0; // A/D変換モジュールのオフを確認します ADCON1bits.ADON=0; ConfigIntADC12(ADC_INT_DISABLE); OpenADC12( Config1, //ADCON1レジスタの設定 Config2, //ADCON2レジスタの設定 Config3, //ADCON3レジスタの設定 ConfigPort, //ADPCFGレジスタの設定 ConfigScan //ADCSSLレジスタの設定 ); /// タイマ1周期 200msec OpenTimer1(T1_ON & //タイマ1ON T1_GATE_OFF & //ゲート制御ON T1_PS_1_256 & //プリスケーラ 1/256 T1_SYNC_EXT_OFF & //クロック同期制御OFF T1_SOURCE_INT , //クロック源:内部クロック 23030 //200msec → 200×1000×(117.92MHz/4MHz)/256=23031.25 ); //PR1 = 23031 -1 = 23030 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"ADC Start !!%u",Count); //arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 delay_ms(1000); ConfigIntTimer1(T1_INT_PRIOR_5 & T1_INT_ON); //割込みレベル5 タイマ1割込みON EnableIntT1; //割込み許可 while(1) //タイマ割込みを待つ { } CloseADC12(); //AD変換終了処理 return 0; } //********************************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //********************************************************************************************* #include "p30f2012.h" #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //******************************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //******************************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
AN3端子の入力電圧(デジタルテスタ表示値)が 概略 0v、 2.5v、 5.0vの時の液晶表示を以下に示します。
AN3の入力電圧 | ||||
0V | 2.5V | 5V | ||
(2)入力電圧を液晶に表示(dsPIC30F4013)
dsPIC30F4013の内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。
<試作品仕様>
・ dsPIC30F4013のAN1端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+5V(PICの電源電圧)とする。
・ 液晶には以下を200msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
<試作品回路図>
dsPIC30F4013の場合の回路図を以下にしめします。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> ///************************************************************/ // ADコンバータ出力の液晶表示 // dsPIC30F4013 //************************************************************/ #include "p30f4013.h" #include "1lcd_lib_C30.h" #include "adc12.h" #include "stdio.h" _FOSC(CSW_FSCM_OFF & XT_PLL8); // (10MHz)x8=80MHz _FWDT(WDT_OFF); _FBORPOR(PBOR_ON & BORV_42 & PWRT_64 & MCLR_EN); _FGS(CODE_PROT_OFF); unsigned int Config1 = //ADCON1レジスタの設定 ADC_MODULE_ON & //ADON bit15=1 : ADコンバータモジュール → ON //AD Module On/Off ADC_IDLE_CONTINUE & //ADSIL bit13=0 : アイドル時の動作 → 動作継続 //Idle Mode Operation ADC_FORMAT_INTG & //FORM bit9-8=00 :出力データのフォーマット → 整数 //Result Output Format ADC_CLK_AUTO & //SSRC bit5-7=111 :変換開始トリガ設定 //Conversion Trigger Source // →ADCON3のSAMCによるクロック(サンプルホールド)が終了後変換自動開始 ADC_AUTO_SAMPLING_OFF & //ASAM bit2=1 : ADサンプリング自動開始→手動開始 //Auto Sampling Select ADC_SAMP_OFF; //SAMP bit1=0 : サンプリング手動制御→OFF //Sample Enable // (例)ASAM = 0(ADC_AUTO_SAMPLING_OFF) の時 SAMP=1(ADC_SAMP_ON)で変換開始 //DONE bit0 : AD変換終了フラグ(AD変換が終了すると1が立つ、 書き込み不可) unsigned int Config2 = //ADCON2レジスタの設定 ADC_VREF_AVDD_AVSS & //VCFG bit13-15=000: S/Hアンプのリファレンス設定: 基準電圧Vdd、シングルエンド //Voltage Reference ADC_SCAN_OFF & //CSCNA bit10=0 : MUX交互自動スキャン制御→オフ //Scan Section ADC_SAMPLES_PER_INT_1 & //SMPI bit2-5 : 割込み頻度→1回毎 //Number of Samples between Interrupts ADC_ALT_BUF_OFF & //BUFM bit1=0: 交互バッファー制御→なし //Buffer mode Select ADC_ALT_INPUT_OFF; //ALTS bit0=0: AD入力の複数バッファーへの格納//Alternate Input sample Mode Select( unsigned int Config3 = //ADCON3レジスタの設定 ADC_SAMPLE_TIME_8 & //SAMC bit8-12 :サンプルホールド時間 → 8サイクル(TAD)//Auto Sample Time bits ADC_CONV_CLK_SYSTEM & //ADRC bit7=0 :AD変換クロック→システムクロック //Conversion Clock Source Select ADC_CONV_CLK_32Tcy; //ADCS bit0-5 :変換クロック数→32Tcy(設定のMAXを選択) //Conversion Clock Select unsigned int ConfigPort = //ADPCFGレジスタの設定 ANLOG/DIGITAl Pin Select //ex1. ENABLE_ALL_ANA ex2. ENABLE_ALL_DIG ex3. ENABLE_AN0_ANA & ENABLE_AN1_ANA ENABLE_AN1_ANA; //AN1 → アナログポート unsigned int ConfigScan = //ADCSSLレジスタの設定 Scan Channel Select SCAN_NONE; //ADCSLL = 0x0000 : 自動スキャン→スキャンせず unsigned int Channel1 = //ADCHSレジスタの設定 ADC_CH0_POS_SAMPLEA_AN1 & //マルチプレクサA(S/Hアンプ)のVref+への接続チャンネル → チャンネル1 ADC_CH0_NEG_SAMPLEA_NVREF; //マルチプレクサA(S/Hアンプ)のVref-への接続チャンネル → Vss unsigned int Count; unsigned int AdcValue; char Buf[17]; //文字列のバッファー用レジスタ void delay_ms(unsigned int); void AdcFunc(void); void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/4000*N); } void AdcFunc(void) // AD変換読み取り & 液晶表示 { float Volt; unsigned int I; unsigned int F; SetChanADC12(Channel1); //Vref-(RB1、AN1) → GND ADCON1bits.SAMP =1; //サンプリング開始 //サンプルホールド時間:8TAD (ADCON3のSAMC<3:0>) //変換の自動開始 //変換時間:31TAD (ADCON3のADCS<5:0>) // while(BusyADC12()); while(!ADCON1bits.DONE); //AD変換終了フラグが1になるまでまつ // AdcValue = ReadADC12(0); //AD変換値読込み(読込みが遅い) C30のバグ? AdcValue = ADCBUF0; //AD変換値読込み(読込みが早い) //バッファー0の読み出し lcd_clear(); //全消去 sprintf(Buf,"AdV=%u",AdcValue); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 Count++; Volt =(float)AdcValue/4095*5; I = (unsigned int) Volt; F = (unsigned int)(( Volt - I)*1000); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"Volt=%u.%u[V]",I,F); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 delay_ms(200); //200msec毎に再表示 } /// メイン関数 int main(void) { TRISB = 0b0000000000000010; // AD入力のbit1(AN1 RB1)のみ入力 TRISF = 0; OpenADC12( Config1, //ADCON1レジスタの設定 Config2, //ADCON2レジスタの設定 Config3, //ADCON3レジスタの設定 ConfigPort, //ADPCFGレジスタの設定 ConfigScan //ADCSSLレジスタの設定 ); lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"ADC Start !!%u",Count);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 delay_ms(1000); while(1) { AdcFunc(); // AD変換読み取り & 液晶表示 } CloseADC12(); //AD変換終了処理 return 0; } //********************************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //********************************************************************************************* #include "p30f4013.h" #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //********************************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //********************************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
AN1端子の入力電圧(デジタルテスタ表示値)が 概略 0v、 2.5v、 5.0vの時の液晶表示を以下に示します。
AN1端子の入力電圧 | ||||
0V | 2.5V | 5V | ||
■ C30コンパイラ PIC24編
入力電圧を液晶に表示する。
PIC24FJ64GA002の内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。
<試作品仕様>
・ PIC24FJ64GA002のAN0端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+3.3V(PICの電源電圧)とする。
・ 液晶には以下を200msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
<試作品回路図>
PIC24FJ64GA002の場合の回路図を以下にしめします。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> ///************************************************************/ //* AD変換 液晶表示 //* PIC24FJ64GA002 //************************************************************/ #include "p24FJ64GA002.h" #include <stdio.h> //#include <adc10.h> //★(dsPICと同じようには)インクルードできない #include <timer.h> #include "1lcd_lib_C30.h" #include "1lcd_lib_c30.c" /// コンフィギュレーション ビットの設定 _CONFIG1( JTAGEN_OFF & //JTAGポート: OFF GCP_OFF & //コードプロテクト: OFF GWRP_OFF & //書き込みプロテクト: OFF BKBUG_OFF & //バックグランドデバック: OFF COE_OFF & //クリップオン エミュレーション: OFF ICS_PGx1& //ICDピンの選択: EMUC/EMUDをPGC1/PGD1と共用 FWDTEN_OFF )//ウォッチドックタイマ: OFF _CONFIG2( IESO_OFF & // 2速度スタートアップ機能:OFF FNOSC_FRCPLL & //内臓高速RC発振(8MHZ)回路 + 4倍PLL → 32MHz(= 8MHz × 4) FCKSM_CSDCMD & //クロック切替え制御:OFF クロックモニタ:OFF OSCIOFNC_OFF & //OSCO/RC15 function: OSCO or Fosc/2 IOL1WAY_OFF & //RP Register Protection: Unlimited Writes To RP Registers I2C1SEL_PRI & //I2C1 pins Select: Use Primary I2C1 pins POSCMOD_NONE) //発振回路モード Oscillator Selection: Primary disabled unsigned int AdcValue; char Buf[17]; //文字列のバッファー用レジスタ unsigned int Count=0; void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/4000*N); } void AdcFunc(void) // AD変換読み取り & 液晶表示 { float Volt; unsigned int I; unsigned int F; AD1CON1bits.SAMP =1; //サンプリング開始 while(!AD1CON1bits.DONE); //AD変換終了フラグがたつ(1になるまで)待つ // delay_ms(1); AdcValue = ADC1BUF0; //ADC1のAN0のバッファーからAD変換結果を読込む lcd_clear(); //全消去 sprintf(Buf,"AdV=%u",AdcValue); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 Volt =(float)AdcValue/1024*3.3; I = (unsigned int) Volt; F = (unsigned int)(( Volt - I)*1000); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"Volt=%u.%u[V]",I,F); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 } void _ISR _T1Interrupt(void) //タイマ1割込み { IFS0bits.T1IF = 0; //フラグクリア AdcFunc(); // AD変換読み取り & 液晶表示 } /// メイン関数 int main(void) { TRISA = 0xFFFF; //Aポートを入力モードに設定 TRISB = 0; //Bポートを出力モードに設定 //AD1CON1レジスタの設定 AD1CON1bits.ADON = 1; //A/Dコンバータモジュール有効 AD1CON1bits.ADSIDL = 0; //アイドルモード中もモジュール動作継続 AD1CON1bits.FORM1 = 0; //AD1CON1bits.FORM0 と2ビットでセット AD1CON1bits.FORM0 = 0; //00: 符号なし整数 (参考)11:符号なし固定少数、10:固定少数、01:整数 //★ Michrochip PIC24FJ64GA002のデータシートでは00がIntegerとなっているがUnsigned Integerの誤植である。 AD1CON1bits.SSRC2 = 1; //AD1CON1bits.SSRC2-AD1CON1bits.SSRC0 でセット AD1CON1bits.SSRC1 = 1; //111: 内蔵カウンタでサンプリングを終了させ変換を開始する AD1CON1bits.SSRC0 = 1; //(参考)000: SAMPビットでサンプリングを終了し変換を開始する AD1CON1bits.ASAM = 0; //SAMPビットのセットでサンプリングを開始する。 (参考)1: 自動開始(前の変換終了後すぐサンプリングを開始する) AD1CON1bits.SAMP = 0; //サンプリング停止 //AD1CON2レジスタの設定 AD1CON2bits.VCFG2 = 0; //AD1CON2bits.VCFG2 - AD1CON2bits.VCFG0(VCFG<2:0>)の3ビットでセット AD1CON2bits.VCFG1 = 0; //000:リファレンス電圧 → Vdd -Vss AD1CON2bits.VCFG0 = 0; //(参考)001:リファレンス電圧 → 外部入力 - Vss 他 AD1CON2bits.CSCNA = 1; //マルチプレクサMUXAでのスキャン: する AD1CON2bits.SMPI3 = 0; //AD1CON2bits.SMPI3 - AD1CON2bits.SMPI0(SMPI<3:0>)の4ビットでセット AD1CON2bits.SMPI2 = 0; //0000: AD変換完了毎の割り込み発生(割り込み有効の場合) AD1CON2bits.SMPI1 = 0; //(参考)0011: 4サンプルのAD変換終了後 割り込み発生(割り込み有効の場合) AD1CON2bits.SMPI0 = 0; // AD1CON2bits.BUFM = 0; //バッファーを1個の16ワードバッファとする。 (参考)1: 2組の8ワードバッファーとする AD1CON2bits.ALTS = 0; //常にMUXAを入力マルチプレクサにする (参考)1: MUXA,MUXBを交互につかう //AD1CON3レジスタの設定 AD1CON3bits.ADRC = 0; //AD変換クロック源:システムクロック (参考)1: A/D内臓RCクロック AD1CON3bits.SAMC4 = 1; //AD1CON3bits.SAMC4 - AD1CON3bits.SAMC0(SAMC<4:0>)の5ビットでセット AD1CON3bits.SAMC3 = 1; //アクイジションタイム(Tad(クロック周期)×N)設定 AD1CON3bits.SAMC2 = 1; //1111: 31Tad AD1CON3bits.SAMC1 = 1; //(参考)0001: 1Tad 0010: 2Tad 0011: 3Tad ・・・・ AD1CON3bits.SAMC0 = 1; // AD1CON3bits.ADCS7 = 0; //AD1CON3bits.ADCS7 - AD1CON3bits.ADCS0(ADCS<7:0>)の8ビットでセット AD1CON3bits.ADCS6 = 0; //AD変換のクロックとクロック源の関係 AD1CON3bits.ADCS5 = 0; //0000 0101: 1Tad = 5Tcy AD1CON3bits.ADCS4 = 0; //(参考) 0000 0000: 1Tad = 0.5Tcy AD1CON3bits.ADCS3 = 0; // 0000 0001: 1Tad = 1.0Tcy AD1CON3bits.ADCS2 = 1; // 0000 0010: 1Tad = 1.5Tcy AD1CON3bits.ADCS1 = 0; // ・・・・ AD1CON3bits.ADCS0 = 1; // 1111 1111: 1Tad = 128Tcy //AD1CHSレジスタの設定 AD1CHSbits.CH0NB = 0; //マルチプレクサMUXB用負側入力選択ビット: VR- (参考)1: AN1 AD1CHSbits.CH0SB3 = 0; //AD1CHSbits.CH0SB3 - AD1CHSBbits.CH0SB0(<CH0SB<3:0>)の4ビットでセット AD1CHSbits.CH0SB2 = 0; //マルチプレクサMUXBの正側入力選択 AD1CHSbits.CH0SB1 = 0; //0000: AN0 AD1CHSbits.CH0SB0 = 0; //(参考)0001: AN1 0011 AN2 .... 1111: AN15 AD1CHSbits.CH0NA = 0; //マルチプレクサMUXA用負側入力選択ビット: VR- (参考)1: AN1 AD1CHSbits.CH0SA3 = 0; //AD1CHSbits.CH0SA3 - AD1CHSbits.CH0SA0(<CH0SA<3:0>)の4ビットでセット AD1CHSbits.CH0SA2 = 0; //マルチプレクサMUXAの正側入力選択 AD1CHSbits.CH0SA1 = 0; //0000: AN0 AD1CHSbits.CH0SA0 = 0; //(参考)0001: AN1 0011 AN2 .... 1111: AN15 //AD1PCFGレジスタの設定 // ★デバイスリセットでは全ビット0となるためデフォルトではアナログ入力となるのでデジタルで使う多重ピンは、コンフィグレーションでデジタル設定が必要!! //PIC24FJ64GA002にはないピン・設定も特に必要ないが設定 AD1PCFGbits.PCFG15 = 1;//RA15/AN15アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ // AD1PCFGbits.PCFG14 = 1;//RA14/AN14アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ // AD1PCFGbits.PCFG13 = 1;//RA13/AN13アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG12 = 1;//RA12/AN12アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG11 = 1;//RA11/AN11アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG10 = 1;//RA10/AN10アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG9 = 1;//RA9/AN9アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ // AD1PCFGbits.PCFG8 = 1;//RA8/AN8アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ // AD1PCFGbits.PCFG7 = 1;//RA7/AN7アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ // AD1PCFGbits.PCFG6 = 1;//RA6/AN6アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG5 = 1;//RA5/AN5アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG4 = 1;//RA4/AN4アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG3 = 1;//RA3/AN3アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG2 = 1;//RA2/AN2アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG1 = 1;//RA1/AN1アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG0 = 0;//RA0/AN0アナログ入力orデジタル入力選択: アナログ (参考)0: デジタル // AD1CSSLレジスタの設定 //読み込むチャンネル(入力端子)をセットする AD1CSSLbits.CSSL15 = 0; //AN15をMUXAでスキャンしない (参考)1: スキャンする // AD1CSSLbits.CSSL14 = 0; //AN15をMUXAでスキャンしない (参考)1: スキャンする // AD1CSSLbits.CSSL13 = 0; //AN13をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL12 = 0; //AN12をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL11 = 0; //AN11をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL10 = 0; //AN10をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL9 = 0; //AN9をMUXAでスキャンしない (参考)1: スキャンする // AD1CSSLbits.CSSL8 = 0; //AN8をMUXAでスキャンしない (参考)1: スキャンする // AD1CSSLbits.CSSL7 = 0; //AN7をMUXAでスキャンしない (参考)1: スキャンする // AD1CSSLbits.CSSL6 = 0; //AN6をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL5 = 0; //AN5をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL4 = 0; //AN4をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL3 = 0; //AN3をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL2 = 0; //AN2をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL1 = 0; //AN1をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL0 = 1; //AN0をMUXAでスキャンする (参考)0: スキャンしない /// タイマ1周期 200msec OpenTimer1(T1_ON & //タイマ1ON T1_GATE_OFF & //ゲート制御ON T1_PS_1_64 & //プリスケーラ 1/64 T1_SYNC_EXT_OFF & //クロック同期制御OFF T1_SOURCE_INT, //クロック源:内部クロック 24999 //200msec → 200×1000×(32MHz/4MHz)/64=25000 ); //PR1 = 25000 -1 = 24999 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"ADC Start !!%u",Count);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 delay_ms(1000); ConfigIntTimer1(T1_INT_PRIOR_5 & T1_INT_ON); //割込みレベル5 タイマ1割込みON EnableIntT1; //割込み許可 while(1) //タイマ割込みを待つ { } CloseTimer1(); return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p24FJ64GA002.h" #define Clock 32000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATBbits.LATB1 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATBbits.LATB0 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
液晶の下に写っているのはAN0の端子電圧を表示しているデジタルテスターです。
AN0の入力電圧 | ||
0V | 1.5V | 3.3V |
■ C32コンパイラ PIC32MX編
入力電圧を液晶に表示する。
PIC32MX460F512L内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。
<試作品仕様>
・ PIC32MX460F512LのAN0端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+3.3V(PICの電源電圧)とする。
・ 液晶には以下を100msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
<試作品回路図>
PIC32MX460F512Lの場合の回路図を以下にしめします。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています.
・ QFPのPIC32MX460F512Lは、マイクロチップから開発用ターゲットボードExplore 16のCPUボードとして、販売されている
PIM(Plug in Moduke)に実装されているものを使っています。
・使用しているユニバーサルキバンは自作のユニバーサルキバンです。
<プログラム例> // ADコンバータ読み込み・値の液晶表示 // PIC32MX460F512L #include <proc/p32mx460f512l.h> //PIC32MX460F512L #include <plib.h> // PIC32 peripheral library //for SYSTEMConfigPerformance() #include "1lcd_lib_C32.h" // コンフィギュレーション設定 // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 char Buf[17]; //文字列のバッファー用レジスタ void AdcFunc(void) // AD変換読み取り & 液晶表示 { float Volt; unsigned int I; unsigned int F; unsigned int AdcValue; AD1CON1bits.SAMP =1; //サンプリング開始 while(!AD1CON1bits.DONE); //AD変換終了フラグがたつ(1になるまで)待つ AdcValue = ADC1BUF0; //ADC1のAN0のバッファーからAD変換結果を読込む lcd_clear(); //全消去 sprintf(Buf,"AdV=%u",AdcValue); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 Volt =(float)AdcValue/1024*3.3; I = (unsigned int) Volt; F = (unsigned int)(( Volt - I)*1000); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"Volt=%u.%u[V]",I,F); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 } void __ISR(4,ipl2)T1Hander(void) //タイマ1割込 100msec毎 { mT1ClearIntFlag(); //フラグクリア AdcFunc(); // AD変換読み取り & 液晶表示 } int main(void) { SYSTEMConfigPerformance(80000000); // システム最適化 LATBbits.LATB0 = 1; //RB0/AN0 を入力ポートに設定 TRISE = 0; //Eポートを出力モードに設定 //AD1CON1レジスタの設定 AD1CON1bits.ON = 1; //A/Dコンバータモジュール有効 AD1CON1bits.FRZ = 0; //デバッグモードに於いても動作継続 AD1CON1bits.SIDL = 0; //アイドルモード中もモジュール動作継続 AD1CON1bits.FORM2 = 0; //AD1CON1bits.FORM2-AD1CON1bits.FORM0のセットで出力データ形式指定 → 000:16ビット符号なし整数形式 AD1CON1bits.FORM1 = 0; //011:符号付固定16ビット小数 010:固定小数16ビット 001:符号付き整数16ビット 000:16ビット符号なし整数 AD1CON1bits.FORM0 = 0; //111:符号付32ビット固定小数 110:32ビット固定小数 101:符号付32ビット整数 100=32ビット符号なし整数 //★ Michrochip データシートDS61104 では000、100がIntegerとなっているがUnsigned Integerの誤植である。 AD1CON1bits.SSRC2 = 1; //AD1CON1bits.SSRC2-AD1CON1bits.SSRC0 のセットでトリガーソースを指定 AD1CON1bits.SSRC1 = 1; //111: 内蔵カウンタでサンプリングを終了させ変換を開始する AD1CON1bits.SSRC0 = 1; //(参考)000: SAMPビットでサンプリングを終了し変換を開始する AD1CON1bits.CLRASAM = 0;//AD変換割り込み時の変換停止 0:次の変換値でオーバーライト AD1CON1bits.ASAM = 0; //SAMPビットのセットでサンプリングを開始する。(参考)1: 自動開始(前の変換終了後すぐサンプリングを開始する) AD1CON1bits.SAMP = 0; //サンプリング停止 //AD1CON2レジスタの設定 AD1CON2bits.VCFG2 = 0; //リファレンス選択//AD1CON2bits.VCFG2 - AD1CON2bits.VCFG0(VCFG<2:0>)の3ビットでセット AD1CON2bits.VCFG1 = 0; //000:リファレンス電圧 → Vdd -Vss AD1CON2bits.VCFG0 = 0; //(参考)001:リファレンス電圧 → 外部入力 - Vss 他 AD1CON2bits.OFFCAL = 0; //較正モード設定 0:サンプルホールドアンプSHAの入力はAD1CHSレジスタとAD1CSSLレジスタで制御される AD1CON2bits.CSCNA = 1; //マルチプレクサMUXAでのスキャン: する AD1CON2bits.SMPI3 = 0; //割り込みタイミング AD1CON2bits.SMPI3 - AD1CON2bits.SMPI0(SMPI<3:0>)の4ビットでセット AD1CON2bits.SMPI2 = 0; //0000: AD変換完了毎の割り込み発生(割り込み有効の場合) AD1CON2bits.SMPI1 = 0; //(参考)0011: 4サンプルのAD変換終了後 割り込み発生(割り込み有効の場合) AD1CON2bits.SMPI0 = 0; // AD1CON2bits.BUFM = 0; //バッファーを1個の16ワードバッファとする。 (参考)1: 2組の8ワードバッファーとする AD1CON2bits.ALTS = 0; //常にMUXAを入力マルチプレクサにする (参考)1: MUXA,MUXBを交互につかう //AD1CON3レジスタの設定 AD1CON3bits.ADRC = 0; //AD変換クロック源選択//0: PBCLK(Peripheral Bus Clock) (参考)1: A/D内臓RCクロック AD1CON3bits.SAMC4 = 1; //AD1CON3bits.SAMC4 - AD1CON3bits.SAMC0(SAMC<4:0>)の5ビットでセット AD1CON3bits.SAMC3 = 1; //アクイジションタイム(Tad(クロック周期)×N)設定(ホールドキャパシタ充電所要時間) AD1CON3bits.SAMC2 = 1; //1111: 31Tad AD1CON3bits.SAMC1 = 1; //(参考)0001: 1Tad 0010: 2Tad 0011: 3Tad ・・・・ AD1CON3bits.SAMC0 = 1; // AD1CON3bits.ADCS7 = 0; //AD変換時間の設定/AD1CON3bits.ADCS7 - AD1CON3bits.ADCS0(ADCS<7:0>)の8ビットでセット //AD変換完了フラグAD1CON1bits.DONEにより、AD変換完了を検知する場合は設定不要 AD1CON3bits.ADCS6 = 0; //AD変換完了までののクロック数選択ビット AD1CON3bits.ADCS5 = 0; //0000 0101: 1Tad = 6Tpb (Tpb: PBCLKの周期) AD1CON3bits.ADCS4 = 0; //(参考) 0000 0000: 1Tad = 2Tpb AD1CON3bits.ADCS3 = 0; // 0000 0001: 1Tad = 3Tpb AD1CON3bits.ADCS2 = 1; // 0000 0010: 1Tad = 4Tpb AD1CON3bits.ADCS1 = 0; // ・・・・ AD1CON3bits.ADCS0 = 1; // 1111 1111: 1Tad = 512Tpb //AD1CHSレジスタの設定 //SHAの+端子とー端子への接続(ポート)設定 AD1CHSbits.CH0NB = 0; //マルチプレクサMUXB用負側入力選択ビット: VR- (参考)1: AN1 AD1CHSbits.CH0SB3 = 0; //AD1CHSbits.CH0SB3 - AD1CHSBbits.CH0SB0(<CH0SB<3:0>)の4ビットでセット AD1CHSbits.CH0SB2 = 0; //マルチプレクサMUXBの正側入力選択 AD1CHSbits.CH0SB1 = 0; //0000: AN0 AD1CHSbits.CH0SB0 = 0; //(参考)0001: AN1 0011 AN2 .... 1111: AN15 AD1CHSbits.CH0NA = 0; //マルチプレクサMUXA用負側入力選択ビット: VR- (参考)1: AN1 AD1CHSbits.CH0SA3 = 0; //AD1CHSbits.CH0SA3 - AD1CHSbits.CH0SA0(<CH0SA<3:0>)の4ビットでセット AD1CHSbits.CH0SA2 = 0; //マルチプレクサMUXAの正側入力選択 AD1CHSbits.CH0SA1 = 0; //0000: AN0 AD1CHSbits.CH0SA0 = 0; //(参考)0001: AN1 0011 AN2 .... 1111: AN15 //AD1PCFGレジスタの設定 // ポートのアナログデジタル // ★デバイスリセットでは全ビット0となるためデフォルトではアナログ入力となるのでデジタルで使う多重ピンは、コンフィグレーションでデジタル設定が必要!! AD1PCFGbits.PCFG15 = 1;//RB15/AN15アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG14 = 1;//RB14/AN14アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG13 = 1;//RB13/AN13アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG12 = 1;//RB12/AN12アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG11 = 1;//RB11/AN11アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG10 = 1;//RB10/AN10アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG9 = 1;//RB9/AN9アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG8 = 1;//RB8/AN8アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG7 = 1;//RB7/AN7アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG6 = 1;//RB6/AN6アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG5 = 1;//RB5/AN5アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG4 = 1;//RB4/AN4アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG3 = 1;//RB3/AN3アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG2 = 1;//RB2/AN2アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG1 = 1;//RB1/AN1アナログ入力orデジタル入力選択: デジタル (参考)0: アナログ AD1PCFGbits.PCFG0 = 0;//RB0/AN0アナログ入力orデジタル入力選択: アナログ (参考)1: デジタル // AD1CSSLレジスタの設定 //読み込むチャンネル(入力端子)をセットする AD1CSSLbits.CSSL15 = 0; //AN15をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL14 = 0; //AN15をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL13 = 0; //AN13をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL12 = 0; //AN12をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL11 = 0; //AN11をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL10 = 0; //AN10をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL9 = 0; //AN9をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL8 = 0; //AN8をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL7 = 0; //AN7をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL6 = 0; //AN6をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL5 = 0; //AN5をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL4 = 0; //AN4をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL3 = 0; //AN3をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL2 = 0; //AN2をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL1 = 0; //AN1をMUXAでスキャンしない (参考)1: スキャンする AD1CSSLbits.CSSL0 = 1; //AN0をMUXAでスキャンする (参考)0: スキャンしない ★使用するAN0のチャンネルだけ読み込む lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"ADC Start !!");//C30とは異なり、arguement 不要 lcd_str(Buf); //液晶表示 OpenTimer1( T1_ON | // タイマ1 イネーブル //T1_OFF → タイマ1 ディセーブル T1_SOURCE_INT | //クロックソース:インターナル //T1_SOURCE_EXT → 外部発振器 T1_PS_1_256, //プリスケール 1/256 //1/1、1/2、1/4、1/8、1/16、1/32、1/64、1/256 31249 //PRx値: T0[msec] = 1000/80000000*256*31249 =99.9968 msec //PICMX32は1クロックで1命令 //周期 T0[sec] = 1/Fosc × プリスケーラの逆数 × PRx値 ); ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2); //タイマ1割込ON、割り込みレベル2 INTEnableSystemMultiVectoredInt(); //割り込みをマルチベクタモードで許可 while(1) { } } //************************************************************************* //インクルードファイル 1lcd_lib_C32.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************* #include <proc/p32mx460f512l.h> //PIC32MX460F512L #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATEbits.LATE7 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATEbits.LATE6 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATEbits.LATE5 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATEbits.LATE4 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATEbits.LATE3 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATEbits.LATE2 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C32.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C32コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C32.h" void lcd_delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(Clock/20000000)*usec; do { asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void lcd_delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) lcd_delay_us(1000); } //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 lcd_delay_us(1); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) lcd_delay_us(1); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 lcd_delay_us(50); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 lcd_delay_ms(2); // 2msec待ち else lcd_delay_us(50); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { lcd_delay_ms(20); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(5); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set lcd_delay_ms(1); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
液晶の下に写っているのはAN0の端子電圧を表示しているデジタルテスターです。
AN0の入力電圧 | ||
0V | 1.5V | 3.3V |
■ XC32コンパイラ PIC32MZ編
PIC32MZのADモジュールは PIC32MXとはその構成が大幅に変更になっています。 その為か revision 5 になってようやく 動くようになったようです。
シリコンチップをつくることは はたで思うよりはるかに難しいようです。
PIC32MZ2048ECH100の内臓ADコンバータからAD変換値を読込み、値を液晶に表示した例を紹介します。
<試作品仕様>
・ PIC32MZ2048ECH100のAN25端子から内臓AD変換器をつかい電圧を読み込む
・ リファレンス電圧は+3.3V(PICの電源電圧)とする。
・ 液晶には以下を100msec毎に表示する。
@ 1行目 …… AD変換値
A 2行目 …… 入力電圧(単位:ボルト)
・ 開発環境 …… Harmony: ver. 1.02 XC32: ver.1.34 MPLABX: ver.2.26 PIC32MZ2048ECH100:
revision 5
<試作品回路図>
PIC32MZ2048ECH100の場合の回路図を以下にしめします。(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //以下、 main.c //-------------------------------------------------------------------------------------------------------- /******************************************************************************* MPLAB Harmony Project Main Source File Company: Microchip Technology Inc. File Name: main.c Summary: This file contains the "main" function for an MPLAB Harmony project. Description: This file contains the "main" function for an MPLAB Harmony project. The "main" function calls the "SYS_Initialize" function to initialize the state machines of all MPLAB Harmony modules in the system and it calls the "SYS_Tasks" function from within a system-wide "super" loop to maintain their correct operation. These two functions are implemented in configuration-specific files (usually "system_init.c" and "system_tasks.c") in a configuration-specific folder under the "src/system_config" folder within this project's top-level folder. An MPLAB Harmony project may have more than one configuration, each contained within it's own folder under the "system_config" folder. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. //Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <stddef.h> // Defines NULL #include <stdbool.h> // Defines true #include <stdlib.h> // Defines EXIT_FAILURE #include "system/common/sys_module.h" // SYS function prototypes // ***************************************************************************** // ***************************************************************************** // Section: Main Entry Point // ***************************************************************************** // ***************************************************************************** int main ( void ) { /* Initialize all MPLAB Harmony modules, including application(s). */ SYS_Initialize ( NULL ); while ( true ) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks ( ); } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE ); } /******************************************************************************* End of File */ //以下、app.c //--------------------------------------------------------------------------------------------------- /******************************************************************************* MPLAB Harmony Application Source File Company: Microchip Technology Inc. File Name: app.c Summary: This file contains the source code for the MPLAB Harmony application. Description: This file contains the source code for the MPLAB Harmony application. It implements the logic of the application's state machine and it may call API routines of other MPLAB Harmony modules in the system, such as drivers, system services, and middleware. However, it does not call any of the system interfaces (such as the "Initialize" and "Tasks" functions) of any of the modules in the system or make any assumptions about when those functions are called. That is the responsibility of the configuration-specific system files. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "app.h" # ifndef _MY_INCLUDE_PERIPHERAL #define _MY_INCLUDE_PERIPHERAL #include <peripheral/peripheral.h> #include <peripheral/ports/plib_ports.h> #endif #include "adc_p32mz2048ech100.h" #include "adcp_p32mz2048ech100.h" #include "1lcd_lib_C32.h" #define ADC_ID_1 0 int delay_Clock = 200000000; //200MHz char Buf[17]; //1液晶表示バッファー extern int Flag_Adc; void delay_us(volatile unsigned int usec) //1μsec遅延 { volatile int count; count = (int)(delay_Clock/20000000)*usec; do //実測 at 200MH (Clock=200000000) { //delay_us(1000):1000.4μsec delay_us(100):100.6μsec delay_us(10):10.5μsec delay_us(1):1.5μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void delay_ms(volatile unsigned int msec) //1msec遅延 { volatile unsigned int i; //実測:at200MH (Clock=200000000)//delay_ms(1): 1.0006msec delay_ms(100):100.04msec for(i=0; i<msec; i++) delay_us(1000); } void AdcFunc(void) { unsigned int AdcValue; float Volt; int I,F; //PLIB_ADCP_IndividualTrigger(ADCP_ID_1, ADCP_AN4); AD1CON3bits.RQCONVRT = 1; //個別入力AD変換開始 //Individual ADC Input Conversion Request bit //AdcValue = PLIB_ADCP_ResultGet( ADC_ID_1, ADCP_AN4 ); //AN25用バッファから変換値(unsigned int) 読出し while(!AD1DSTAT1bits.ARDY4); //AN4の変換終了待ち AdcValue = AD1DATA4; //AN4用バッファから変換値(unsigned int) 読出し lcd_cmd(0x80); //1目の先頭へ sprintf(Buf,"AdV=%u ",AdcValue); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 Volt =(float)AdcValue/2048*3.3; lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"Volt=%.2f[V]",Volt); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 Flag_Adc = 0; } // ***************************************************************************** // ***************************************************************************** // Section: Global Data Definitions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* Application Data Summary: Holds application data Description: This structure holds the application's data. Remarks: This structure should be initialized by the APP_Initialize function. Application strings and buffers are be defined outside this structure. */ APP_DATA appData; // ***************************************************************************** // ***************************************************************************** // Section: Application Callback Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary callback funtions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Local Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary local functions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Initialization and State Machine Functions // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void APP_Initialize ( void ) Remarks: See prototype in app.h. */ void APP_Initialize ( void ) { /* Place the App state machine in its initial state. */ appData.state = APP_STATE_INIT; /* TODO: Initialize your application's state machine and other * parameters. */ //液晶ポート入出力設定----------------------------- PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 15 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 14 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 13 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 12 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_A, 10 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_A, 9 ); /* TRISBbits.TRISB15 = 0; //キャラクタ液晶ポート設定 TRISBbits.TRISB14 = 0; //キャラクタ液晶ポート設定 TRISBbits.TRISB13 = 0; //キャラクタ液晶ポート設定 TRISBbits.TRISB12 = 0; //キャラクタ液晶ポート設定 TRISAbits.TRISA10 = 0; //キャラクタ液晶ポート設定 TRISAbits.TRISA9 = 0; //キャラクタ液晶ポート設定 */ //ADCモジュールキャリブレーション PLIB_ADCP_Configure(ADCP_ID_1, ADCP_VREF_VREFP_VREFN, false, false, false, //Reference voltage set to VREF positive and VREF negative //boostVref:false//fractionalOutputOn:false//stopInIdle:false ADCP_CLK_SRC_SYSCLK, (96000000/ 16000000 / 2), 32, 0, 32); //ADC TAD clock:96MHz//Desired TAD clock Frequency:16MHz //oversampleDigFilterSamTime:32//earlyIntEnable:0//class2and3SampleTime:32 AD1CAL1 = 0xF8894530; // Use software calibration values into AD1CALx AD1CAL2 = 0x01E4AF69; AD1CAL3 = 0x0FBBBBB8; AD1CAL4 = 0x000004AC; AD1CAL5 = 0x02000002; PLIB_ADCP_SHModeSelect(ADCP_ID_1, ADCP_SH0, ADCP_SH_MODE_DIFFERENTIAL_UNIPOLAR);//SH0モジュールを差動アンプモードに設定 PLIB_ADCP_SHModeSelect(ADCP_ID_1, ADCP_SH1, ADCP_SH_MODE_DIFFERENTIAL_UNIPOLAR);//SH1モジュールを差動アンプモードに設定 PLIB_ADCP_SHModeSelect(ADCP_ID_1, ADCP_SH2, ADCP_SH_MODE_DIFFERENTIAL_UNIPOLAR);//SH2モジュールを差動アンプモードに設定 PLIB_ADCP_SHModeSelect(ADCP_ID_1, ADCP_SH3, ADCP_SH_MODE_DIFFERENTIAL_UNIPOLAR);//SH3モジュールを差動アンプモードに設定 PLIB_ADCP_SHModeSelect(ADCP_ID_1, ADCP_SH4, ADCP_SH_MODE_DIFFERENTIAL_UNIPOLAR);//SH4モジュールを差動アンプモードに設定 PLIB_ADCP_SHModeSelect(ADCP_ID_1, ADCP_SH5, ADCP_SH_MODE_DIFFERENTIAL_UNIPOLAR);//SH5モジュールを差動アンプモードに設定 PLIB_ADCP_ChannelScanConfigure(ADCP_ID_1, 0, 0, ADCP_SCAN_TRG_SRC_TMR3_MATCH); PLIB_ADCP_Enable(ADCP_ID_1); //ADC有効化、 シリコンチップキャリブレーションを実行//Turn on the ADC. Wait for silicon ADC self cal to finish while(!PLIB_ADCP_ModuleIsReady(ADCP_ID_1)); //ADC準備完了を待つ //アプリケーションでのADC設定 //PLIB_ADCP_Disable(ADC_ID_1); AD1CON1bits.ADCEN = 0; //PLIB_ADCP_SHModeSelect(ADC_ID_1, ADCP_SH5, ADCP_SH_MODE_SINGLE_ENDED_UNIPOLAR); AD1IMODbits.SH5MOD = 0b00; //No5SHを シングルエンド入力、出力ユニポーラエンコードの unsigned intに設定 //PLIB_ADC_InputSelectPositive(ADC_ID_1, ADC_INPUT_POSITIVE_AN4);//未サポート関数 AD1CON3bits.ADINSEL = 4; //AD変換入力ポート AN4設定 //PLIB_PORTS_PinDirectionInputSet( PORTS_ID_0, PORT_CHANNEL_B, 4 ); TRISBbits.TRISB4 = 1; //RB4 入力モード設定 //PLIB_PORTS_PinModeSelect(PORTS_ID_0, PORTS_ANALOG_PIN_4, PORTS_PIN_MODE_ANALOG); ANSELBbits.ANSB4 = 1; //RB4/AN4 アナログモード //PLIB_ADC_VoltageReferenceSelect(ADC_ID_1, ADC_REFERENCE_VDD_TO_AVSS ); ? //リファレンス電圧設定: Vrefh = AVdd, Vrefl = AVss//未サポート関数 AD1CON3bits.VREFSEL = 0b000; //リファレンス電圧設定: Vrefh = AVdd, Vrefl = AVss //PLIB_ADC_ConversionClockSourceSelect(ADC_ID_1, ADC_CLOCK_SOURCE_SYSTEM_CLOCK); //未サポート関数 AD1CON2bits.ADCSEL = 0b01; //AD変換クロックソース:システムクロック(200MHz) //ADC Clock Source //System Clock //外部入力の場合 0b10: REFCLK3(PPS) //内蔵高速クロック(8MHz)の場合0b11: FRC //0b00 = Reserved // PLIB_ADC_ConversionClockSet(ADC_ID_1, SYS_CLK_FREQUENCY, 19); //This function sets the ADC module conversion clock prescaler//未サポート関数 AD1CON2bits.ADCDIV = 19; //AD変換クロック分周比:1/20 変換周波数:200MHz --> 10MHz (Tad = 100nsec) // 1MHz < 10MHz < 16MHz 故 OK //PLIB_ADC_SampleAcqusitionTimeSet(ADC_ID_1, 50 ); //サンプル時間(アクイジション時間)50Tad//未サポート関数 AD1CON2bits.SAMC = 50; //サンプル時間(アクイジション時間)50Tad = 100nsec x 50 = 5000nec = 5μsec //PLIB_ADCP_Enable(ADC_ID_1); //PLIB_ADC_Enable(ADC_ID_1); //ADC モジュール 有効 // Enable the ADC module AD1CON1bits.ADCEN = 1; //ADC モジュール 有効 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_cmd(0x80); //1目の先頭へ sprintf(Buf,"AD converter ");// lcd_str(Buf); //液晶表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf," Start !! "); // lcd_str(Buf); // 開始メッセージ1行目表示 delay_ms(2000); } /****************************************************************************** Function: void APP_Tasks ( void ) Remarks: See prototype in app.h. */ void APP_Tasks ( void ) { /* Check the application's current state. */ switch ( appData.state ) { /* Application's initial state. */ case APP_STATE_INIT: { if(Flag_Adc == 1)AdcFunc(); //割込み発生時 break; } /* TODO: implement your application state machine.*/ /* The default state should never be executed. */ default: { /* TODO: Handle error in application's state machine. */ break; } } } /******************************************************************************* End of File */ //以下、system_init.c //--------------------------------------------------------------------------------------------------- /******************************************************************************* System Initialization File File Name: system_init.c Summary: This file contains source code necessary to initialize the system. Description: This file contains source code necessary to initialize the system. It implements the "SYS_Initialize" function, configuration bits, and allocates any necessary global system resources, such as the systemObjects structure that contains the object handles to all the MPLAB Harmony module objects in the system. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "system_config.h" #include "app.h" #include "system_definitions.h" // **************************************************************************** // **************************************************************************** // Section: Configuration Bits // **************************************************************************** // **************************************************************************** //----------------------------------------------------------------------- //DEVCFG0レジスタ #pragma config EJTAGBEN = NORMAL #pragma config DBGPER = ALLOW_PG2 #pragma config FSLEEP = OFF #pragma config FECCCON = OFF_UNLOCKED #pragma config BOOTISA = MIPS32 #pragma config TRCEN = OFF #pragma config ICESEL = ICS_PGx2 #pragma config JTAGEN = OFF //JTAG ポート Disable #pragma config DEBUG = OFF //---------------------------------------------------------------------- //DEVCFG1レジスタ #pragma config FNOSC = SPLL //PLL回路(システムPLL)選択 //システム発振回路 //内蔵FRC(8MHz)選択の場合:FNOSC = FRCDIV //Oscillator Selection Bits (Fast RC Osc w/Div-by-N (FRCDIV)) #pragma config FDMTEN = OFF //デッドマンタイマ OFF (Deadman Timer is disabled) //#pragma config DMTINTV = WIN_127_128 // DMT Count Window Interval (Window/Interval value is 127/128 counter value) #pragma config FSOSCEN = OFF // 副発振器OFF //Secondary Oscillator Enable (Disable SOSC) #pragma config IESO = OFF //ウェイクアップ時の2段速度スタートアップ // Internal/External Switch Over (Disabled) #pragma config POSCMOD = HS //HS: ハイスピードレゾネータモード // HS(High Speed Resonator Operation) Oscillator mode selected //EC: 外部発振器 //EC(External Clock Input Operation) mode selected // Primary Oscillator Configuration (Primary osc disabled) #pragma config OSCIOFNC = OFF //OSCCOピン出力無効 #pragma config FCKSM = CSECME //クロック発振:切替及びモニタ有効 //主発振器失陥でFRC(内蔵高速発振器)に切替 //FSCM(Fail Safe Clock Monitor)制御 #pragma config FWDTEN = OFF // ウォッチドックタイマ OFF //Watchdog Timer Disable //#pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576) //#pragma config WDTSPGM = STOP // Watchdog Timer Stop During Flash Programming (WDT stops during Flash programming) //#pragma config WINDIS = NORMAL // Watchdog Timer Window Mode (Watchdog Timer is in non-Window mode) //#pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window size is 25%) //-------------------------------------------------------------------------------------------------------------------- // DEVCFG2レジスタ //システムクロック:200MHz //ペリフェラル周波数://default: 100MHz //PBxDIVで8系統毎に設定変更可 //PBxDIV: PERIPHERAL BUS CLOCK DIVISOR CONTROL レジスタのPBDIV<6:0>: Peripheral Bus Clock Divisor Control ビットで設定 #pragma config FPLLRNG = RANGE_13_26_MHZ //PLL Input周波数入力範囲設定// System PLL Input Range (13-26 MHz Input) //24MHz故 #pragma config FPLLIDIV = DIV_3 //PLL入力側での分周: 1/3 // PLL Input周波数 = 24MHz ÷ 3 = 8MHz // System PLL Input Divider (1x Divider) //#pragma config FPLLICLK = PLL_POSC //主発振回路選択 //内蔵FRC(8MHz)の場合はFPLLICLK = PLL_FRC// System PLL Input Clock Selection (POSC is input to the System PLL) #pragma config FPLLICLK = PLL_FRC //内蔵高速発振器選択 //★★★ バグ有 主発振回路選択の時、FPLLICLK = PLL_POSCではなくFPLLICLK = PLL_FRCを選択する。(at ver.1.33 XC32) #pragma config FPLLMULT = MUL_50 //PLL倍率:50倍 //8MHz x 50 = 400MHz //System PLL Multiplier (PLL Multiply by 50) #pragma config FPLLODIV = DIV_2 //PLL出力側での分周: 1/2 //システムクロック = 400MHz ÷ 2 = 200MHz #pragma config UPLLFSEL = FREQ_24MHZ //USBのPLL入力を 24MHz→12MHzに変換 // USB PLL Input Frequency Selection (USB PLL input is 12 MHz) #pragma config UPLLEN = ON //USBのPLL変換:イネーブル // USB PLL Enable (USB PLL is enabled) //-------------------------------------------------------------------------------------------------------------------------- //DEVCFG3レジスタ #pragma config USERID = 0xffff #pragma config FMIIEN = ON #pragma config FETHIO = ON #pragma config PGL1WAY = ON #pragma config PMDL1WAY = ON #pragma config IOL1WAY = ON #pragma config FUSBIDIO = ON /*** BF1SEQ0 ***/ #pragma config TSEQ = 0xffff #pragma config CSEQ = 0xffff // ***************************************************************************** // ***************************************************************************** // Section: Library/Stack Initialization Data // ***************************************************************************** // *****************************************************************************/ // ***************************************************************************** // ***************************************************************************** // Section: Driver Initialization Data // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // Section: System Data // ***************************************************************************** // ***************************************************************************** /* Structure to hold the object handles for the modules in the system. */ SYSTEM_OBJECTS sysObj; // ***************************************************************************** // ***************************************************************************** // Section: Module Initialization Data // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* System Clock Initialization Data */ const SYS_CLK_INIT sysClkInit = { .moduleInit = {0}, .systemClockSource = SYS_CLK_SOURCE, .systemClockFrequencyHz = SYS_CLK_FREQ, .waitTillComplete = true, .secondaryOscKeepEnabled = true, .onWaitInstruction = SYS_CLK_ON_WAIT, }; /*** System Device Control Initialization Data ***/ const SYS_DEVCON_INIT sysDevconInit = { .moduleInit = {0}, }; // ***************************************************************************** // ***************************************************************************** // Section: Static Initialization Functions // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void DRV_TMR0_Initialize(void) Summary: Initializes Timer Driver Instance 0 Remarks: */ void DRV_TMR0_Initialize(void) { /* Setup TMR0 Instance */ PLIB_TMR_Stop(TMR_ID_1); /* Disable Timer */ PLIB_TMR_ClockSourceSelect(TMR_ID_1, TMR_CLOCK_SOURCE_PERIPHERAL_CLOCK); /* Select clock source */ PLIB_TMR_PrescaleSelect(TMR_ID_1, TMR_PRESCALE_VALUE_256); /* Select prescalar value */ PLIB_TMR_Mode16BitEnable(TMR_ID_1); /* Enable 16 bit mode */ PLIB_TMR_Counter16BitClear(TMR_ID_1); /* Clear counter */ PLIB_TMR_Period16BitSet(TMR_ID_1, 0); /*Set period */ /* Setup Interrupt */ PLIB_INT_SourceEnable(INT_ID_0, INT_SOURCE_TIMER_1); PLIB_INT_VectorPrioritySet(INT_ID_0, INT_VECTOR_T1, INT_PRIORITY_LEVEL1); PLIB_INT_VectorSubPrioritySet(INT_ID_0, INT_VECTOR_T1, INT_SUBPRIORITY_LEVEL0); PLIB_TMR_Period16BitSet(TMR_ID_1,9766); //5 nsec x20 x 9766 x 256 =250.0096msec = 250msec PLIB_TMR_Start(TMR_ID_1); //タイマスタート } // ***************************************************************************** // ***************************************************************************** // Section: System Initialization // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void SYS_Initialize ( SYS_INIT_DATA *data ) Summary: Initializes the board, services, drivers, application and other modules. Remarks: See prototype in system/common/sys_module.h. */ void SYS_Initialize ( void* data ) { /* Core Processor Initialization */ SYS_CLK_Initialize(&sysClkInit); sysObj.sysDevcon = SYS_DEVCON_Initialize(SYS_DEVCON_INDEX_0, (SYS_MODULE_INIT*)&sysDevconInit); SYS_DEVCON_PerformanceConfig(SYS_DEVCON_SYSTEM_CLOCK); SYS_DEVCON_SystemUnlock(); PB3DIVbits.PBDIV = 0x13; //19: タイマ1用ペリフェラルクロック: 1/20 --> 10MHz( = 200MHz/20) //PBCLK3 is SYSCLK divided by 10 // PB3DIVbits.PBDIV = 0x03; //PBCLK3 is SYSCLK divided by 4 SYS_DEVCON_SystemLock(); /* System Services Initialization */ SYS_INT_Initialize(); /* Initialize Drivers */ /* Timer Instanace 0 Call */ DRV_TMR0_Initialize(); /* Initialize System Services */ /* Initialize Middleware */ /* Enable Global Interrupts */ SYS_INT_Enable(); /* Initialize the Application */ APP_Initialize(); } /******************************************************************************* End of File */ //以下、 system_interrupt.c //----------------------------------------------------------------------------------------------------------------------- /******************************************************************************* System Interrupts File File Name: system_int.c Summary: Raw ISR definitions. Description: This file contains a definitions of the raw ISRs required to support the interrupt sub-system. Summary: This file contains source code for the interrupt vector functions in the system. Description: This file contains source code for the interrupt vector functions in the system. It implements the system and part specific vector "stub" functions from which the individual "Tasks" functions are called for any modules executing interrupt-driven in the MPLAB Harmony system. Remarks: This file requires access to the systemObjects global data structure that contains the object handles to all MPLAB Harmony module objects executing interrupt-driven in the system. These handles are passed into the individual module "Tasks" functions to identify the instance of the module to maintain. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2011-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <xc.h> #include <sys/attribs.h> #include "app.h" #include "system_definitions.h" # ifndef _MY_INCLUDE_PERIPHERAL #define _MY_INCLUDE_PERIPHERAL #include <peripheral/peripheral.h> #include <peripheral/ports/plib_ports.h> #endif int Flag_Adc = 0; //AD変換フラグ // ***************************************************************************** // ***************************************************************************** // Section: System Interrupt Vector Functions // ***************************************************************************** // ***************************************************************************** void __ISR(_TIMER_1_VECTOR, ipl2) _IntHandlerDrvTmrInstance0(void) { PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_1);//タイマ1割り込みフラグクリア //IFS0bits.T1IF= 0; //タイマ1割り込みフラグクリア PLIB_TMR_Period16BitSet(TMR_ID_1,9766); //5 nsec x20 x 9766 x 256 =250.0096msec = 250msec Flag_Adc = 1; } /******************************************************************************* End of File */ //以下、1lcd_lib_C32.h //------------------------------------------------------------------------------------------------------------ //************************************************************************* //インクルードファイル 1lcd_lib_C32.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************* #include <p32xxxx.h> #define lcd_Clock 200000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //のDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_rs LATAbits.LATA9 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 #define lcd_stb LATAbits.LATA10 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //以下、1lcd_lib_C32.c //---------------------------------------------------------------------------------------------------------------------- //************************************************************************** //インクルードファイル 1lcd_lib_C32.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C32コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C32.h" void lcd_delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(lcd_Clock/20000000)*usec; do //実測: at 200MH (Clock=200000000) { //delay_us(1000)→1000.4μsec、 delay_us(100)→100.6μsec、delay_us(10)→10.5μsec、delay_us(1)→1.5μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void lcd_delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) lcd_delay_us(1000); } //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 lcd_delay_us(3); //1μsecウェイト // lcd_delay_us(1); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) lcd_delay_us(3); //1μsecウェイト // lcd_delay_us(1); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 lcd_delay_us(50); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 lcd_delay_ms(2); // 2msec待ち else lcd_delay_us(50); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { lcd_delay_ms(20); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(5); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set lcd_delay_ms(1); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
AD入力電圧 | 液晶上段: ADコンバータ読込整数値 液晶下段: 電圧換算値 テスター表示: 電圧値[V] |
Vin = 0v | |
Vin = 1v | |
Vin = 2v | |
Vin = 3v | |
Vin = 3.3v |